package Model;

import java.io.Serializable;
import java.util.ArrayList;

public class Giocatore implements Comparable <Giocatore> , Serializable{
	
	private final String name;
	private int money ;
	private int pv;
	private static final int MIN_BET_MULT=100; //moltiplicatore di scommessa minima
	private String scuderia;
	private  Carta_personaggio character_card;  
	private ArrayList<Carta_azione> action_cards;		 
	private ArrayList <Scommessa> bet_list; 
	
	/**
	 * costruttore crea un oggetto personaggio settando pv a 1 e min_bet a 100
	 * @param nome
	 * @param carta_personaggio
	 */
	public Giocatore(String nome , Carta_personaggio cp) {
		this.name = nome;
		this.pv=1;
		this.action_cards = new ArrayList<Carta_azione>();
		this.bet_list= new ArrayList<Scommessa>();
		this.character_card = cp;
		this.scuderia = cp.get_scuderia();
		this.money = cp.get_soldi();
	} 

//<----------------------------------------------GETTER------------------------------------------------------>
	
	/**
	 * ritorna il nome del giocatore
	 * @return
	 */
	public String get_nome()
	{
		return this.name;
	}
	
	/**
	 * ritorna i soldi del giocatore
	 * @return
	 */
	public int get_money() {
		return this.money;		
	}
	
	/**
	 * ritorna i pv del giocatore
	 * @return
	 */
	public int  get_pv() {
		return this.pv;		
	}
	
	/**
	 * ritorna la la scommessa minima che il giocatore
	 * deve effettuare 
	 * @return
	 */
	public int get_min_bet() {
		return MIN_BET_MULT*pv;		
	}
	
	/**
	 * ritorna la scuderia posseduta dal giocatore
	 * @return
	 */
	public String get_scuderia() {
		return this.scuderia;
	}
	
	/**
	 * ritorna la carta personaggio del giocatore
	 * @return
	 */
	public Carta_personaggio get_character_card(){
		return this.character_card;
	}
	
	/**
	 * ritorna le carte azione di cui il giocatore dispone sotto forma di arraylist
	 * senza esporre il rep.
	 * @return
	 */
	public ArrayList<Carta_azione> get_action_cards(){
		ArrayList<Carta_azione> carte_azione = new ArrayList<Carta_azione>();
		for (Carta_azione carta_azione : action_cards) {
			carte_azione.add(carta_azione);			
		}
		return carte_azione;
	}
	
	/**
	 * Ritorna scommesse del giocatore creando nuovo oggetto Arralist Scommessa quindi non esponendo il rep
	 * @return 
	 */
	public ArrayList <Scommessa> get_scommesse(){
		ArrayList<Scommessa> scommesse =new ArrayList<Scommessa>();
		for (Scommessa bet : bet_list) {
			scommesse.add(bet);		//non necessario clonare bet perche scommessa e immutabile
			
		}
		return scommesse; // come dicevamo occhio al rep.
	}
	
//<----------------------------------------------GESTIONE PUNTI VITTTORIA------------------------------------------------------>
	
	
	
	/**
	 * sottrae pv al giocatore e aggiorna scommessa minima se rimangono 0 pv viene lanciata eccezione (giocatore da eliminare dal gioco)
	 * @param pv
	 * @return ritorna false se giocatore non ha abbastanza pv e true se ne ha
	 */
	public boolean sub_pv (int pv) {
		this.pv=this.pv-pv;
		if(this.pv<=0){
			return false;
		}	
		return true;
	}
	
	/**
	 * aggiunge pv al giocatore separata da sottrai solo per chiarezza e aggiorna la scommessa minima che dipende da essi
	 * @param pv
	 */
	public void add_pv(int pv) {
		this.pv=this.pv+pv;
	}
	
	
//<----------------------------------------------GESTIONE CARTE------------------------------------------------------>
	
	/**
	 * Elimina tutte le carte azione possedute dal giocatore
	 */
	public void drop_card()
	{
		this.action_cards.clear();
		
	}
	
	/**
	 * elimina tutte le scommesse effettuate dal giocatore per tornare ad una
	 * situazione pulita e ricominciare il round.
	 */
	public void drop_scommesse() {
		bet_list.clear();
	}
	
	/**
	 * giocaotre gioca carta su un cavallo => tolgo carta da giocatore e aggiungo a cavallo !!!IMP IO PASSO A CAVALLO LA CARTA SE è IMMUTABILE NON C'è PROBLEMA ALTRIMENTI...PARLARE CON FABIO
	 * @param carta
	 * @param horse
	 * @throws IllegalArgumentException quando il giocatore cerca di giocare una carta che non ha
	 */
	public void play_action_card(Carta_azione carta,Cavallo horse){
		for (Carta_azione card : action_cards) {
			if (card.getNome().equals(carta.getNome())) {
				horse.add_carta_azione(carta);
				action_cards.remove(card);
				return;
			}
			
		}
		throw new IllegalArgumentException();
	}
	
	/**
	 * aggiunge una carta azione al giocatore 
	 * @param carta
	 */
	public void add_action_card(Carta_azione carta){
		action_cards.add(carta);		
	}	
	
	/**
	 * Ritorna una delle due carte appartenenti al giocatore 
	 * @param i e' la carta che voglio ottenere
	 * @return
	 */
	public Carta_azione  get_card_at_index(int i) {
		return action_cards.get(i);
	}
	
//<----------------------------------------------GESTIONE SCOMMESSA------------------------------------------------------>
	

	
	/**
	 * Aggiunge una scommessa al giocatore
	 * @param denaro  denaro della scommessa deve essere maggiore di scommessa min del giocatore altrimenti eccezione viene sollevata
	 * @param colore	colore cavallo su cui scommette
	 * @param tipo		 scommessa Vincente o Piazzata
	 * @throws IllegalArgumentException
	 */	
	public void Scommette(int denaro,String colore,String tipo) throws IllegalArgumentException{
		if (denaro<MIN_BET_MULT*pv) 
			{ throw new IllegalArgumentException("Denaro deve essere maggiore della scommessa minima"); }
		else if (denaro>this.money) {
			throw new IllegalArgumentException("Non hai abbastanza soldi per questa scommessa"); 
		}
		else { 
			Scommessa bet = new Scommessa(denaro, colore, tipo);					//eseguito nella prima scommessa per creare array scommesse
			bet_list.add(bet);
			this.money=this.money-denaro;
		}
		
	}

//<----------------------------------------------METODI GENERALI------------------------------------------------------>

	/**
	 * setta i soldi al giocatore 
	 * @param denaro
	 */
	public void set_money(int denaro) {
		this.money=denaro;
		
	}
	
	/**
	 * assegna la scuderia ( il colore ) al giocatore
	 * @param color
	 */
	public void set_scuderia(String color)
	{
		this.scuderia = color;
	}



	/**
	 * La compareTo viene implementata per ordinare i giocatori che
	 * arrivano alla fine sulla base dei pv che hanno e dei soldi 
	 * determinando cosi' il vincitore della partita
	 */
	public int compareTo(Giocatore player) {
		if( player == this ) return 0;
		if (get_pv()>player.get_pv()){
			return -1;
		}
		if (get_pv()<player.get_pv()){
			return 1;
		}
		else 
		   {
			if (get_money()>player.get_money())
				{ return -1; }
			if (get_money()<player.get_money())
				{ return 1; }			
		   }
		return 1;
		
	}
	
	/**
	 * Implementazione della equals per rispettare la regola dell'interfaccia
	 * della comparable :
	 * The natural ordering for a class C is said to be consistent with equals if and 
	 * only if e1.compareTo(e2) == 0 has the same boolean value as e1.equals(e2) f class C
	 */
	   public boolean equals(Object o) {
	        if (!(o instanceof Giocatore))
	            return false;
	        Giocatore player = (Giocatore) o;
	        if (player == this) 
	        	return true;
	        else
	        	return false;
	    }
	   
	   public int hashCode() {
		 //  assert false : "hashCode not designed";
		   return this.get_nome().hashCode()+this.get_character_card().getNome().hashCode(); // any arbitrary constant will do 
		   }
}